﻿using Koala.Pro.Common;
using Koala.Pro.Core;
using Koala.Pro.Core.Models;
using Koala.Pro.Models;
using Newtonsoft.Json;
using System.Linq.Expressions;

namespace Koala.Pro.Services
{
    public abstract class MyCrudService<TEntity, TKey, TGetListInput> : BaseCrudService<TEntity, TKey, TGetListInput> where TEntity : class, IEntity<TKey>, new() where TGetListInput : IPagedAndSortedResultRequest
    {
        protected IOperationLogService _logService;

        public MyCrudService()
        {
            if (ServiceLocator.SerivcePovider != null)
            {
                _logService = ServiceLocator.GetService<IOperationLogService>();
            }
        }

        protected async Task<bool> CheckOperationLogEnable(OperationLogTypeEnum logType)
        {
            bool result = false;
            string fullName = typeof(TEntity).FullName;
            OperationLogSettingInfo operationLogSettingInfo = await _logService.GetOperationLogSetting(fullName);
            if (operationLogSettingInfo != null)
            {
                switch (logType)
                {
                    case OperationLogTypeEnum.UPDATE:
                        result = operationLogSettingInfo.UpdateLog > 0;
                        break;
                    case OperationLogTypeEnum.ADD:
                        result = operationLogSettingInfo.InsertLog > 0;
                        break;
                    case OperationLogTypeEnum.DELETE:
                        result = operationLogSettingInfo.DeleteLog > 0;
                        break;
                }
            }
            return result;
        }

        protected override async Task OnOperationLog(TKey id, OperationLogTypeEnum logType)
        {
            if (await CheckOperationLogEnable(logType))
            {
                TEntity val = await base.EntityDb.GetByIdAsync(id);
                if (val != null)
                {
                    string note = JsonConvert.SerializeObject(val, Formatting.Indented);
                    await AddOperationLog(logType.ToString(), note);
                }
            }
            await Task.CompletedTask;
        }

        protected override async Task OnOperationLog(TEntity input, OperationLogTypeEnum logType)
        {
            if (await CheckOperationLogEnable(logType) && input != null)
            {
                if (logType == OperationLogTypeEnum.UPDATE)
                {
                    string changedNote = (await base.EntityDb.GetByIdAsync(input.Id)).GetChangedNote(input);
                    if (!string.IsNullOrEmpty(changedNote))
                    {
                        await AddOperationLog(logType.ToString(), changedNote);
                    }
                }
                else
                {
                    string note = JsonConvert.SerializeObject(input, Formatting.Indented);
                    await AddOperationLog(logType.ToString(), note);
                }
            }
            await Task.CompletedTask;
        }

        protected override async Task OnOperationLog(IEnumerable<TKey> input, OperationLogTypeEnum logType)
        {
            if (input == null)
            {
                return;
            }
            if (await CheckOperationLogEnable(logType))
            {
                List<TEntity> list = base.EntityDb.GetList((TEntity s) => input.Contains(s.Id));
                if (list != null && list.Count > 0)
                {
                    string note = JsonConvert.SerializeObject(list, Formatting.Indented);
                    await AddOperationLog(logType.ToString(), note);
                }
            }
            await Task.CompletedTask;
        }

        protected override async Task OnOperationLog(Expression<Func<TEntity, bool>> input, OperationLogTypeEnum logType)
        {
            if (input != null && await CheckOperationLogEnable(logType))
            {
                List<TEntity> list = await base.EntityDb.GetListAsync(input);
                if (list != null && list.Count > 0)
                {
                    string note = JsonConvert.SerializeObject(list, Formatting.Indented);
                    await AddOperationLog(logType.ToString(), note);
                }
            }
        }

        protected override async Task OnOperationLog(List<TEntity> input, OperationLogTypeEnum logType)
        {
            if (await CheckOperationLogEnable(logType))
            {
                if (input != null && input.Count > 0)
                {
                    if (logType == OperationLogTypeEnum.UPDATE)
                    {
                        List<string> noteList = new List<string>();
                        foreach (TEntity newEntity in input)
                        {
                            string changedNote = (await base.EntityDb.GetByIdAsync(newEntity.Id)).GetChangedNote(newEntity);
                            if (!string.IsNullOrEmpty(changedNote))
                            {
                                noteList.Add(changedNote);
                            }
                        }
                        string note = JsonConvert.SerializeObject(noteList, Formatting.Indented);
                        await AddOperationLog(logType.ToString(), note);
                    }
                    else
                    {
                        string note2 = JsonConvert.SerializeObject(input, Formatting.Indented);
                        await AddOperationLog(logType.ToString(), note2);
                    }
                }
            }
            await Task.CompletedTask;
        }

        public override async Task AddOperationLog(string logType, string note)
        {
            string fullName = typeof(TEntity).FullName;
            await _logService.AddOperationLog(fullName, logType, note);
        }
    }

}
